<!DOCTYPE html>
<html>
<meta charset="utf-8" />
<!-- 生产环境版本，优化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<!-- 开发环境版本，包含了有帮助的命令行警告 -->
<!-- <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> -->
<script src="https://unpkg.com/element-ui@2.7.2/lib/index.js"></script>
<!-- <script src="https://unpkg.com/axios/dist/axios.min.js"></script> -->
<link rel="stylesheet" href="https://unpkg.com/element-ui@2.7.2/lib/theme-chalk/index.css">
<style>

</style>

<body>
	<div id="app">
		<el-row>
			<el-col :span="22" :offset="1">
				<el-card>
					<div slot="header">订阅信息</div>
					<el-container v-loading="loading" element-loading-text="疯狂测速中……">
						<el-form :inline="true">
							<el-form-item label="订阅链接：">
								<el-input v-model="subscription" style="width: 300px" @keyup.enter.native="submit"></el-input>
							</el-form-item>
							<el-form-item label="自定义组名：">
								<el-input v-model="groupname" style="width: 200px" @keyup.enter.native="submit"></el-input>
							</el-form-item>
							<el-form-item>
								<el-button type="primary" @click="submit">提交</el-button>
							</el-form-item>
						</el-form>
					</el-container>
				</el-card>

				<br>
				<!--
				<el-card>
					<div slot="header">操作</div>
					<el-container>
						<el-form :inline="true">
							<el-form-item>
								<el-button type="primary" @click="submit">提交</el-button>
							</el-form-item>
							<el-form-item>
								<el-button type="secondary">终止</el-button>
							</el-form-item>
						</el-form>
					</el-container>
				</el-card>
				
				<br>
				-->
				<el-card>
					<div slot="header">结果</div>
					<el-container>
						<el-table :data="result" :cell-style="colorCell" size="medium" ref="result">
							<el-table-column label="Group" align="center" prop="group" width="300" sortable>
							</el-table-column>
							<el-table-column label="Remark" align="center" prop="remark" width="300" sortable>
							</el-table-column>
							<el-table-column label="Loss" align="center" prop="loss" width="100" sortable>
							</el-table-column>
							<el-table-column label="Ping" align="center" prop="ping" width="100" sortable :sort-method="floatSort">
							</el-table-column>
							<el-table-column label="AvgSpeed" align="center" prop="speed" width="150" sortable :sort-method="speedSort">
							</el-table-column>
							<el-table-column label="MaxSpeed" align="center" prop="maxspeed" width="150" sortable :sort-method="speedSort">
							</el-table-column>
						</el-table>
					</el-container>
				</el-card>
			</el-col>
		</el-row>

	</div>


	<script>
		let colorgroup = [
			[255, 255, 255],
			[128, 255, 0],
			[255, 255, 0],
			[255, 128, 192],
			[255, 0, 0]
		]
		let bounds = [0, 64 * 1024, 512 * 1024, 4 * 1024 * 1024, 16 * 1024 * 1024]
		
		let interval=0

		let resultjson = []

		let app = new Vue({
			el: '#app',
			data: {
				loading: false,
				subscription: 'https://home.jiyou.fun/modules/servers/V2raySocks/osubscribe.php?sid=3638&token=3ryiHWBXpFxB',
				groupname: '',
				method: 'SOCKET',
				result: [],
			},
			created() {
				document.title = 'Stair Speedtest Web GUI'
			},
			methods: {
				submit: function () {
					this.loading = true
					this.starttest(this.subscription, this.groupname)
				},
				colorCell: function ({
					row,
					column,
					rowIndex,
					columnIndex
				}) {
					let style = 'color: black; font-weight: 600;'
					let speed = 0
					switch(columnIndex)
					{
					case 4:
						speed = row.speed
						break
					case 5:
						speed = row.maxspeed
						break
					default:
						return style
					}
					if (isNaN(parseFloat(speed))) return style
					let color = this.getSpeedColor(this.getSpeed(speed))
					return style + 'background: ' + color
				},
				useNewPalette() {
					colorgroup = [
						[255, 255, 255],
						[102, 255, 102],
						[255, 255, 102],
						[255, 178, 102],
						[255, 102, 102],
						[226, 140, 255],
						[102, 204, 255],
						[102, 102, 255]
					];
					bounds = [0, 64 * 1024, 512 * 1024, 4 * 1024 * 1024, 16 * 1024 * 1024, 24 * 1024 * 1024, 32 * 1024 * 1024, 40 * 1024 * 1024];
				},
				getSpeed(speed) {
					let value = parseFloat(speed.toString().slice(0, -2))
					if (speed.toString().slice(-2) == "MB") {
						value *= 1048576
					}
					else if (speed.toString().slice(-2) == "KB") {
						value *= 1024
					}
					else value = parseFloat(speed.toString().slice(0, -1))
					return value
				},
				getColor(lc, rc, level) {
					let colors = [];
					let r, g, b;
					colors.push(parseInt(lc[0] * (1 - level) + rc[0] * level));
					colors.push(parseInt(lc[1] * (1 - level) + rc[1] * level));
					colors.push(parseInt(lc[2] * (1 - level) + rc[2] * level));
					return colors;
				},
				getSpeedColor(speed) {
					for (let i = 0; i < bounds.length - 1; i++) {
						if (speed >= bounds[i] && speed <= bounds[i + 1]) {
							let color = this.getColor(colorgroup[i], colorgroup[i + 1], ((speed - bounds[i]) / (bounds[i + 1] - bounds[i])))
							return 'rgb(' + color[0] + ',' + color[1] + ',' + color[2] + ')'
						}
					}
					return 'rgb(' + colorgroup[colorgroup.length - 1][0] + ',' + colorgroup[colorgroup.length - 1][1] + ',' + colorgroup[colorgroup.length - 1][2] + ')'
				},
				connect(url) {
					try {
						ws = new WebSocket(url)
					} catch (ex) {
						this.loading=false
						//this.$message.error('Cannot connect: ' + ex)
						this.$alert("后端连接错误！请检查后端运行情况！原因："+ex,"错误")
						return;
					}
				},
				disconnect() {
					if (ws) {
						ws.close()
					}
				},
				send(msg) {
					if (ws) {
						try {
							ws.send(msg)
						} catch (ex) {
							this.$message.error('Cannot send: ' + ex)
						}
					} else {
						this.loading=false
						//this.$message.error('Cannot send: Not connected')
						this.$alert("后端连接错误！请检查后端运行情况！","错误")
					}
				},
				starttest(link, group) {
					this.result = [];
					this.connect("ws://"+window.location.host)
					if (ws) {
						ws.addEventListener('open', function (ev) {
							this.send(link + "^" + group)
						})
						ws.addEventListener('message', this.MessageEvent)
					} else {
						this.loading=false
						this.$alert("后端连接错误！请检查后端运行情况！","错误")
					}
				},
				loopevent(id,tester) {
					item = this.result[id]
					switch (tester) {
						case "ping":
							item.ping="测试中..."
							item.loss="测试中..."
							this.$set(this.result, id, item)
							break
						case "speed":
							item.speed="测试中..."
							item.maxspeed="测试中..."
							this.$set(this.result, id, item)
							break
					}
				},					
				MessageEvent(ev) {
					console.log(ev.data)
					let json = JSON.parse(ev.data)
					let id = parseInt(json.id)

					let item = {}
					switch (json.info) {
						case "gotserver":
							item = {
								"group": this.groupname==""?json.group:this.groupname,
								"remark": json.remarks,
								"loss": "",
								"ping": "",
								"speed": "0.00B",
								"maxspeed": "0.00B"
							}
							this.$set(this.result, id, item)
							break
						case "startping":
							//inverval=setInterval("app.loopevent("+id+",\"ping\")",300)
							this.loopevent(id,"ping")
							break
						case "gotping":
							//clearInterval(interval)
							item = this.result[id]
							item.loss = json.loss
							item.ping = json.ping
							/*
							item = {
								"group": json.group,
								"remark": json.remarks,
								"loss": json.loss,
								"ping": json.ping,
								"speed": "0.00KB"
							}
							*/
							this.$set(this.result, id, item)
							break
						case "startspeed":
							//inverval=setInterval("app.loopevent("+id+",\"speed\")",300)
							this.loopevent(id,"speed")
							break
						case "gotspeed":
							//clearInterval(interval)
							item = this.result[id]
							item.speed = json.speed
							item.maxspeed = json.maxspeed
							/*
							item = {
								"group": json.group,
								"remark": json.remarks,
								"loss": json.loss,
								"ping": json.ping,
								"speed": json.speed
							}
							*/
							this.$set(this.result, id, item)
							break
						case "picsaving":
							app.$notify.info("保存结果图片中……")
							break
						case "picsaved":
							app.$notify.success("图片已保存！路径："+json.path)
							break
						case "eof":
							this.loading = false
							break
						case "retest":
							item = this.result[id]
							this.$notify.error("节点 "+item.group+" - "+item.remark+" 第一次测试无速度，将重新测试。")
							break
						case "nospeed":
							item = this.result[id]
							this.$notify.error("节点 "+item.group+" - "+item.remark+" 第二次测试无速度。")
							break
						case "error":
							switch (json.reason) {
								case "noconnection":
									item = this.result[id]
									item.ping="0.00"
									item.loss="100.00%"
									this.$notify.error("节点 "+item.group+" - "+item.remark+" 无法连接。")
									this.$set(this.result, id, item)
									break
								case "nonodes":
									this.$alert("找不到任何节点。请检查订阅链接。","错误")
									break
								case "invalidsub":
									this.$alert("订阅获取异常。请检查订阅链接。","错误")
									break
								case "unhandled":
									this.$alert("程序异常退出！","错误")
									break
							}
							console.log("error:" + json.reason)
							break
					}
					console.log(this.result)
				},
				floatSort: function (obj1, obj2) {
					return parseFloat(obj1.ping) - parseFloat(obj2.ping)
				},
				speedSort: function (obj1, obj2) {
				/*
					let unit1 = obj1.speed.substr(-2, 2)
					let unit2 = obj2.speed.substr(-2, 2)
					let value1 = obj1.speed.slice(0, -2)
					let value2 = obj2.speed.slice(0, -2)

					if (unit1 === unit2) {
						return parseFloat(value1) - parseFloat(value2)
					} else if (unit1 === 'MB') {
						return parseFloat(value1) * 1024 - parseFloat(value2)
					} else {
						return parseFloat(value1) - parseFloat(value2) * 1024
					}
				*/
					return getSpeed(obj1.speed) - getSpeed(obj2.speed)
				}
			}
		})
	</script>
</body>

</html>